/********************************************************************************
*                                                                               *
* kWookaApplicationLoggerPanel.cpp -- Show logger information                   *
*                                                                               *
* Copyright (c) Fengren Technology(Guangzhou) Co.LTD. All rights reserved.      *
*                                                                               *
********************************************************************************/


#include "kWookaApplicationLoggerPanel.hpp"

#include "kWooka_ids.h"
#include "kWookaApplicationViewPanel.hpp"
#include "kWooka_frame.hpp"
#include "kWookaProjectInfo.hpp"
#include "kWookaExecuteProcess.hpp"
#include <wx/txtstrm.h>
#include <wx/mstream.h>
#include "kWooka_perferences_utils.hpp"

BEGIN_EVENT_TABLE(kWookaApplicationLoggerPanel, wxPanel)
    ////Manual Code Start
    EVT_BUTTON(ID_WXBTN_CLEAR, kWookaApplicationLoggerPanel::OnClear)
    EVT_BUTTON(ID_WXBTN_SEARCH, kWookaApplicationLoggerPanel::OnSearch)
    EVT_RADIOBUTTON(ID_RADIO_LIST_CTRL, kWookaApplicationLoggerPanel::OnRadioListChanged)
    EVT_RADIOBUTTON(ID_RADIO_TEXT_CTRL, kWookaApplicationLoggerPanel::OnRadioTextChanged)
    EVT_SPINCTRL(ID_SPIN_CACHELINES, kWookaApplicationLoggerPanel::OnCacheLineChanged)
    ////Manual Code End
    //EVT_KEY_DOWN(kPosSimpleCheckoutPanel::OnKeyCharEvent)
    EVT_THREAD(ID_THREAD_EVENT_LOG, kWookaApplicationLoggerPanel::OnLoggingEvent)
END_EVENT_TABLE()



kWookaApplicationLoggerPanel::kWookaApplicationLoggerPanel(wxWindow *parent, wxWindowID id, const wxString& WXUNUSED(title), const wxPoint &position, const wxSize& size, long style)
: wxPanel(parent, id, position, size, style)
{
    CreateGUIControls();
}

kWookaApplicationLoggerPanel::~kWookaApplicationLoggerPanel()
{
    wxLogDebug(wxT("kWookaApplicationLoggerPanel destroyed."));
}

void kWookaApplicationLoggerPanel::CreateGUIControls()
{
    //Do not add custom code between
    //GUI Items Creation Start and GUI Items Creation End
    //wxDev-C++ designer will remove them.
    //Add the custom code before or after the blocks
    ////GUI Items Creation Start

    CreateContentPanel();
    
    Center();

    ////GUI Items Creation End
}

/**
    Create the Search panel
    1. Status, 2. Order No, 3. Order Name, 4. Pay Time
 */
void kWookaApplicationLoggerPanel::CreateContentPanel() {
    m_searchCtrl = new wxSearchCtrl(this, ID_SEARCH_LOGS);
    m_loglistList = new wxListBox(this, ID_WX_LOGGER_LISTBOX);
    m_loglistText = new wxTextCtrl(this, ID_WX_LOGGER_LISTBOX, wxT(""), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY);

    wxButton* wxBtnSearch = new wxButton(this, ID_WXBTN_SEARCH, _("Search"), wxPoint(500, 270), wxSize(145, 24), 0, wxDefaultValidator, _T("WxButton2"));
    wxButton* wxBtnClear = new wxButton(this, ID_WXBTN_CLEAR, _("Clear"), wxPoint(500, 270), wxSize(145, 24), 0, wxDefaultValidator, _T("WxButton3"));
    wxStaticText* wxTextNothing = new wxStaticText(this, wxID_ANY, wxT(""), wxPoint(500, 270), wxSize(145, 24), 0, _T("wxStaticText1"));

    wxStaticText* lblLogStyle = new wxStaticText(this, wxID_ANY, _("Logger Style"), wxPoint(500, 270), wxSize(120, 24), 0, _T("wxStaticText1"));
    wxStaticText* lblLogCachlines = new wxStaticText(this, wxID_ANY, _("Cache Lines"), wxPoint(500, 270), wxSize(120, 24), 0, _T("wxStaticText1"));

    kWookaSpinCtrl = new wxSpinCtrl(this, ID_SPIN_CACHELINES, wxT("500"), wxDefaultPosition, wxSize(60, 24), wxSP_ARROW_KEYS,100, 5000, 500);
    
    kWookaListCtrl = new wxRadioButton(this, ID_RADIO_LIST_CTRL, _("LIST"));
    kWookaTextCtrl = new wxRadioButton(this, ID_RADIO_TEXT_CTRL, _("TEXT"));

    kWookaListCtrl->SetToolTip(_("It uses ListBox for logger window. It may need less memory and fast."));
    kWookaTextCtrl->SetToolTip(_("It uses TextCtrl for logger window. It may need more memory."));
    
    wxBoxSizer* boxSizer = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer* searchBoxSizer = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer* clearBoxSizer = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer* lblBoxSizer = new wxBoxSizer(wxHORIZONTAL);

    lblBoxSizer->Add(lblLogStyle, 0, wxEXPAND | wxRIGHT, 0);
    lblBoxSizer->Add(kWookaListCtrl, 0, wxEXPAND | wxRIGHT, 10);
    lblBoxSizer->Add(kWookaTextCtrl, 0, wxEXPAND | wxRIGHT, 10);
    lblBoxSizer->Add(wxTextNothing, 0, wxEXPAND | wxALL, 0);
    lblBoxSizer->Add(lblLogCachlines, 0, wxEXPAND | wxALL, 0);
    lblBoxSizer->Add(kWookaSpinCtrl, 0, wxEXPAND | wxALL, 0);

    searchBoxSizer->Add(m_searchCtrl, 1, wxEXPAND | wxALL, 5);
    searchBoxSizer->Add(wxBtnSearch, 0, wxEXPAND | wxALL, 5);
    clearBoxSizer->Add(lblBoxSizer, 1, wxEXPAND | wxALL, 5);
    clearBoxSizer->Add(wxBtnClear, 0, wxEXPAND | wxALL, 5);

    boxSizer->Add(searchBoxSizer, 0, wxEXPAND | wxALIGN_TOP | wxALL, 0);
    boxSizer->Add(clearBoxSizer, 0, wxEXPAND | wxALIGN_TOP | wxALL, 0);
    boxSizer->Add(m_loglistText, 1, wxEXPAND | wxALL, 5);
    boxSizer->Add(m_loglistList, 1, wxEXPAND | wxALL, 5);
    m_loglistText->Hide();
    m_toggleList = true;
    kWookaListCtrl->SetValue(true);
    m_cachedlines = 500;
    this->SetSizerAndFit(boxSizer);
}

void kWookaApplicationLoggerPanel::OnKeyCharEvent(wxKeyEvent& event){
    if (event.GetKeyCode() == WXK_RETURN){
    }
}

void kWookaApplicationLoggerPanel::SetViewPanel(kWookaApplicationViewPanel* vp) {
    m_viewpanel = vp;
}

kWookaApplicationViewPanel* kWookaApplicationLoggerPanel::GetViewPanel() {
    return m_viewpanel;
}


void kWookaApplicationLoggerPanel::UpdateLoggerUI() {
    if (this->GetViewPanel() == NULL) {
        return;
    }

    kWookaAppItemInfo* appitem = this->GetViewPanel()->GetAppItem();

    if (appitem != NULL && this->GetViewPanel()->GetWookaFrame()->GetProjectInfo() != NULL) {
        kWookaProcessExecutor* executor = this->GetViewPanel()->GetWookaFrame()->GetProjectInfo()->runtime->GetExecutor(appitem->id);
        if (executor != NULL) {
            executor->Attach(this);
#ifdef USE_CACHE_LOGS
            wxArrayString& logs = executor->GetLogs();
#else
            wxArrayString logs = executor->ReadLogs(m_cachedlines);
#endif 
            m_loglistText->Clear();
            m_loglistList->Clear();
            m_logscrolled = 0;
            if (!logs.IsEmpty()) {
                if (m_toggleList) {
                    int ps = logs.size() - m_cachedlines;
                    m_loglistList->InsertItems(logs, 0);
                    m_loglistList->ScrollLines(m_loglistList->GetCount());
                }
                else {
                    wxString splines;
                    for (wxArrayString::const_iterator it = logs.begin(); it != logs.end(); ++it) {
                        splines.Append(*it).Append(wxT("\n"));
                        // splines += *it + wxT("\n");
                    }

                    m_loglistText->AppendText(splines);
                    /*
                    wxString* ptext = wxArrayStringJoin(logs, L"\n");
                    
                    if (ptext != NULL) {
                        m_loglistText->SetValue(*ptext);
                        delete ptext;
                    }
                    */
                    splines.Clear();
                }
#ifndef USE_CACHE_LOGS
                logs.Clear();
#endif
            }
        }
    }
}

void kWookaApplicationLoggerPanel::OnLoggingEvent(wxThreadEvent& te) {
    if (m_loglistText != NULL && m_loglistList != NULL) {
        wxAny any;
        kWookaLogger* log = static_cast<kWookaLogger*>(te.GetPayload<kWookaLogger*>());
        if (log != NULL) {
            if (m_toggleList) {
                m_loglistList->Insert(te.GetString(), m_loglistList->GetCount());
                m_loglistList->Append(log->logTexts);
                m_loglistList->ScrollLines(m_loglistList->GetCount());
                while (m_loglistList->GetCount() > m_cachedlines) {
                    m_loglistList->Delete(0);
                }
            }
            else {
                wxString splines;
                for (wxArrayString::const_iterator it = log->logTexts.begin(); it != log->logTexts.end(); ++it) {
                    // m_loglist->AppendText(*it + "\n");
                    splines.Append(*it).Append(wxT("\n"));
                }
                m_loglistText->AppendText(splines);
            }
            log->logTexts.Clear();
            delete log;
        }
    }
}

void kWookaApplicationLoggerPanel::OnClear(wxCommandEvent& WXUNUSED(event)) {
    if (m_loglistList != NULL && m_loglistText != NULL) {
        m_loglistText->Clear();
        m_loglistList->Clear();
        m_logscrolled = 0;
        if (this->GetViewPanel()->GetAppItem() != NULL && GetViewPanel()->GetWookaFrame()->GetProjectInfo() != NULL) {
            wxString id = this->GetViewPanel()->GetAppItem()->id;
            GetViewPanel()->GetWookaFrame()->GetProjectInfo()->runtime->GetExecutor(id)->GetLogs().Clear();
        }
    }
}

void kWookaApplicationLoggerPanel::OnSearch(wxCommandEvent& WXUNUSED(event)) {
    wxString search = m_searchCtrl->GetValue();
    wxString text = this->m_loglistText->GetValue();

    size_t st = text.Index(search);
    if (st >= 0) {
        this->m_loglistText->SetSelection(st, st + search.length());
    }

}

void kWookaApplicationLoggerPanel::OnRadioListChanged(wxCommandEvent& WXUNUSED(event)) {
    wxDateTime dt = wxDateTime::Now();
    wxLogDebug(dt.FormatISOTime());
    if (kWookaListCtrl->GetValue()) {
        this->m_loglistList->Show(true);
        this->m_loglistText->Show(false);
        m_toggleList = true;
        ///Change the value into list
        m_loglistText->Clear();
    }
    else if (kWookaTextCtrl->GetValue()) {
        this->m_loglistList->Show(false);
        this->m_loglistText->Show(true);
        m_toggleList = false;
        m_loglistList->Clear();
    }
    UpdateLoggerUI();
    this->Layout();
    wxDateTime ndt = wxDateTime::Now();
    wxLogDebug(ndt.FormatISOTime());
}

void kWookaApplicationLoggerPanel::OnRadioTextChanged(wxCommandEvent& evt) {
    OnRadioListChanged(evt);
}

void kWookaApplicationLoggerPanel::OnCacheLineChanged(wxSpinEvent& WXUNUSED(event)) {
    this->m_cachedlines = this->kWookaSpinCtrl->GetValue();
    while (m_loglistList->GetCount() > m_cachedlines) {
        m_loglistList->Delete(0);
    }
}